﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Timers;
using System.ComponentModel;
using System.Collections.Generic;

namespace wifi_test
{
    class cls_testnet
    {
        private enum ThreadState { idle, handshake, testing, sendhandshake, getdstinfo, getdstinfoovertime };

        private MainForm MF;    //用于记录下主窗口
        private IPEndPoint _DestIP;
        private int _LocalSendPort; //用于记录下这个对象所对应的本机发送端口
        private int _LocalRecPort;  //用于记录下这个对象所对应的本机接收端口
        private UdpClient _SendClient;
        private UdpClient _RecClient;

        private Thread testThread;
        private Thread testRecThread;
        private Thread testSendThread;
        private Thread testGetDstInfoThread;

        private ThreadState _state;
        private int _recPackets;
        private int _recframeno;
        private int _recErrors;
        private int _recMiss;
        private int _sendPackets;
        private static Semaphore _lockthread;   //用于锁定线程的信号
        private IPEndPoint _DestCmdIp;  //用于记录下目标机的指命的接口

        private cls_XML _XML_cls;

        private uint _dstSystemSendCount;    //目标机系统发送的包
        private uint _dstSystemRecCount;     //目标机系统接收的包
        private uint _dstRecCount;          //目标机驱动接收的包
        private uint _dstSendCount;         //目标机驱动发送的包

        public System.Timers.Timer runTimeOverTimer;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="mf">主窗口</param>
        /// <param name="destIP">目标机的地址</param>
        /// <param name="localsendport">本机所对应于这个类的发送端口</param>
        /// <param name="localrecport">本机所对应于这个类的接收端口</param>
        /// 作者:xhd
        /// 创建日期:09.10.29
        public cls_testnet(MainForm mf, IPEndPoint destIP, int localsendport, int localrecport)
        {
            MF = mf;
            _DestIP = destIP;
            _LocalSendPort = localsendport;
            _LocalRecPort = localrecport;
            _SendClient = new UdpClient(localsendport);
            //_RecClient = new UdpClient(localrecport);

            _recPackets = 0;
            _recframeno = 0;
            _recErrors = 0;
            _recMiss = 0;
            _sendPackets = 0;

            _dstSystemSendCount = 0;    //目标机系统发送的包
            _dstSystemRecCount = 0;     //目标机系统接收的包
            _dstRecCount = 0;          //目标机驱动接收的包
            _dstSendCount = 0;         //目标机驱动发送的包

            _lockthread = new Semaphore(1, 1);

            testThread = new Thread(new ParameterizedThreadStart(this.sub_ClsThread));
            testThread.IsBackground = true;
            _state = ThreadState.idle;

            testRecThread = new Thread(new ParameterizedThreadStart(this.sub_ClsRecThread));
            testRecThread.IsBackground = true;

            testSendThread = new Thread(new ParameterizedThreadStart(this.sub_ClsSendThread));
            testSendThread.IsBackground = true;

            testGetDstInfoThread = new Thread(new ParameterizedThreadStart(this.sub_ClsGetDstInfoThread));
            testGetDstInfoThread.IsBackground = true;

            _DestCmdIp = new IPEndPoint(destIP.Address, destIP.Port + 1);

            _XML_cls = new cls_XML();
            _XML_cls.fun_InitXML(_DestIP.Address.ToString() + "-Data.xml");
        }


        /// <summary>
        /// 析造函数
        /// </summary>
        ~cls_testnet()
        {
            _lockthread.WaitOne();  //锁住信号没有释放

            if (_state == ThreadState.testing)
            {
                _XML_cls.fun_WirteXML(MainForm.xmlevnet.end, System.DateTime.Now.ToString(), null);
            }

            if (testRecThread.IsAlive)
            {
                _SendClient.Close();
                try
                {
                    testRecThread.Suspend();
                    testRecThread.Abort();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
                //testRecThread.clos
            }
            if (testSendThread.IsAlive)
            {
                _SendClient.Close();
                try
                {
                    testSendThread.Suspend();
                    testSendThread.Abort();
                }
                catch(Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
                //testSendThread.Abort();
            }
            if (testGetDstInfoThread.IsAlive)
            {
                _RecClient.Close();
                try
                {
                    testGetDstInfoThread.Suspend();
                    testGetDstInfoThread.Abort();
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
            _lockthread.Release();
        }


        /// <summary>
        /// 启动相关的线程
        /// </summary>
        public void sub_StartThread()
        {
            testThread.Start(0);
            
            string xustr = "线程" + _DestIP.ToString();
            MF.xulog(MainForm.LogMsgType.Incoming, xustr + "准备启动测试" + "\n");
        }


        /// <summary>
        /// 对于这个类的测试主线程
        /// </summary>
        private void sub_ClsThread(Object param)
        {
            sub_SendHandShake();
            _state = ThreadState.sendhandshake;
            runTimeOverTimer = new System.Timers.Timer();
            runTimeOverTimer.Interval = 3 * 1000;   //3秒
            runTimeOverTimer.Elapsed += new ElapsedEventHandler(runTimeOverTimer_Elapsed);
            runTimeOverTimer.Enabled = true;
            //准备要接收目标机传来的数据了

            testRecThread.Start(0); //启动了接收数据的线程
        }


        /// <summary>
        /// 发送数据的线程
        /// </summary>
        /// <param name="param"></param>
        private void sub_ClsSendThread(object param)
        {
            int i;
            byte[] sendbuf;

            i = _sendPackets;
            while (true)
            {
                _lockthread.WaitOne();

                #region 这段代码被_lockthread所保护

                if (i > 9)
                {
                    i = i % 10;
                }

                sendbuf = fun_CreateFrame(Convert.ToByte(i));
                if (sendbuf != null)
                {
                    _SendClient.Send(sendbuf, sendbuf.Length, _DestIP);
                    //Thread.Sleep(1);   //停下10ms
                    //Thread.Sleep(1);       
                }
                i += 1;
                _sendPackets += 1;

                #endregion

                _lockthread.Release();
            }
        }


        /// <summary>
        /// 接收目标所送出来的数据阻塞
        /// </summary>
        /// <returns></returns>
        private byte[] fun_RecDstData()
        {
            IPEndPoint sendAddress = new IPEndPoint(IPAddress.Any, 0);

            //byte[] retbuf = cls_RecUdp.Receive(ref sendAddress);
            byte[] retbuf;
            try
            {
                retbuf = _SendClient.Receive(ref sendAddress);
                if (sendAddress.Address.ToString() != _DestIP.Address.ToString())
                {
                    //地址不相等
                    retbuf = null;
                }
            }
            catch (Exception e)
            {
                //MF.xulog(Form1.LogMsgType.Warning, e.ToString() + "\n");
                Console.WriteLine(e.ToString());
                retbuf = null;
            }

            return retbuf;
        }


        /// <summary>
        /// 监控这个对象的接收端口
        /// </summary>
        /// <param name="param"></param>
        private void sub_ClsRecThread(Object param)
        {
            int ret;
            while (true)
            {
                byte[] recbuf = fun_RecDstData();
                if (recbuf != null)
                {
                    //要进行接收的数据分析了
                    ret = fun_AnalyFrame(recbuf, _state);
                    if (ret == 100)
                    {
                        //返回表示是握手成功
                        if (_state == ThreadState.sendhandshake)
                        {
                            //要进入到测试了
                            _state = ThreadState.testing;
                            string xustr = "线程" + _DestIP.ToString() + "--握手成功，开始测试\n";
                            MF.xulog(MainForm.LogMsgType.Incoming, xustr);
                            _XML_cls.fun_WirteXML(MainForm.xmlevnet.start, System.DateTime.Now.ToString(), null);
                            runTimeOverTimer.Interval = 60 * 1000;  //1分钟
                            runTimeOverTimer.Enabled = true;
                            testSendThread.Start(0);
                        }
                        else if (_state == ThreadState.getdstinfo)
                        {
                            //取得目标机信息状态
                        }
                    }

                    recbuf = null;
                }
                else
                {
                    //目标机已经退出了
                    _state = ThreadState.idle;
                    string xustr1 = "目标机" + _DestIP.ToString() + "--退出了测试环境\n";
                }
            }
        }


        /// <summary>
        /// 发送握手信号
        /// </summary>
        private void sub_SendHandShake()
        {
            string xustr = "ready?";
            byte[] data_sp = new byte[32];

            Array.Copy(System.Text.Encoding.Default.GetBytes(xustr), data_sp, 6);
            int i = _SendClient.Send(data_sp, data_sp.Length, _DestIP);
        }


        /// <summary>
        /// 运行时的主超时器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void runTimeOverTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            System.Timers.Timer handleTimer = (System.Timers.Timer)sender;

            string xustr;
            int ret;

            handleTimer.Enabled = false;

            switch (_state)
            {
                case ThreadState.sendhandshake:
                    //没有接收到握手信号
                    //xustr = "线程" + _DestIP.ToString();
                    //MF.xulog(MainForm.LogMsgType.Error, xustr + "握手超时" + "\n");
                    sub_SendHandShake();
                    handleTimer.Interval = 3 * 1000;
                    handleTimer.Enabled = true;
                    break;

                case ThreadState.testing:
                    //要取目标机信息了
                    testGetDstInfoThread.Start(0);  //启动取得目标机信息的线程
                    break;

                case ThreadState.getdstinfo:
                    //取目标机信息指令发出但是超时了
                    _state = ThreadState.getdstinfoovertime;
                    string xust1r = "发送指令失败";
                    _RecClient.Close();
                    MF.xulog(MainForm.LogMsgType.Error, xust1r + "\n");
                    break;
            }
        }


        /// <summary>
        ///  对送入的帧数据进行分析
        /// </summary>
        /// 返回：100表示握手成功了。
        /// 返回：-1这帧不是所期望接收到的帧
        /// 返回：0不做任何处理
        /// 返回： 1这帧是所期望的接收到的帧
        /// <param name="framedata">接收到的帧数据</param>
        /// <returns></returns>
        private int fun_AnalyFrame(byte[] framedata, ThreadState currentState)
        {
            int ret = 0;
            int i;
            byte[] tmpbuf;

            switch (currentState)
            {
                case ThreadState.sendhandshake:
                    //处于握手的状态
                    tmpbuf = new byte[2];

                    if (framedata.Length > 1)
                    {
                        Array.Copy(framedata, tmpbuf, 2);
                        if ((tmpbuf[0] == 111) && (tmpbuf[1] == 107))
                        {
                            ret = 100;
                            _recPackets = 0;
                        }
                        else
                        {
                            ret = 0;
                        }
                    }
                    break;

                case ThreadState.testing:
                    //进行对接收到的包进行判断
                    _recPackets += 1;
                    if (_recframeno == -1)
                    {
                        //刚握手成功还没有接收到过数据
                        _recframeno = framedata[0] + 1;
                        if (_recframeno > 9)
                        {
                            _recframeno = 0;
                        }
                    }
                    else
                    {
                        //要对数据进行判断是否是我要的数据
                        if (_recframeno == framedata[0])
                        {
                            byte dstfirstbyte;

                            dstfirstbyte = 65;
                            dstfirstbyte += (byte)_recframeno;    //第一个102个字节的内容要为a+帧号
                            i = fun_comparadata(framedata, dstfirstbyte);
                            if (i == -1)
                            {
                                //出错了，要调整一下要接收帧号了
                                //要记录下出错的信息了

                                string xustr = "接收帧号" + _recframeno.ToString() + "内容出错";
                                MF.sub_enterlog(MainForm.recordstate.recerror, xustr);
                                _recErrors += 1;
                                _recframeno += 1;
                            }
                            else
                            {
                                _recframeno += 1;
                            }
                        }
                        else
                        {
                            //比较出错了
                            if (((framedata[0] == 0) && (_recframeno == 9)) || ((_recframeno == 9) && (framedata[0] == 0)))
                            {
                                i = 1;
                            }
                            else if (framedata[0] > _recframeno)
                            {
                                i = framedata[0] - _recframeno;
                            }
                            else
                            {
                                i = _recframeno - framedata[0];
                            }
                            string xustr = "希望接收帧号" + _recframeno.ToString() + "--实际接收帧号"
                                            + framedata[0].ToString() + "--掉失" + i.ToString();

                            _recMiss += i;
                            MF.sub_enterlog(MainForm.recordstate.recerror, xustr);

                            _recframeno = framedata[0] + 1;
                        }

                        if (_recframeno > 9)
                        {
                            _recframeno = 0;
                        }
                    }
                    break;

                case ThreadState.getdstinfo:
                    int xu_i;

                    xu_i = 100;
                    break;
            }
            return ret;
        }


        /// <summary>
        /// 对接收到的数据进行每102字一块的比较
        /// </summary>
        /// <param name="data_sp">接收到的数据</param>
        /// <param name="dstValue">第一个块应为的数据内容</param>
        /// <returns>
        /// 返回1正常
        /// 返回-1不是希望的
        /// </returns>
        private int fun_comparadata(byte[] data_sp, byte dstValue)
        {
            int ret = 1;
            int i;
            byte tmpbyte;

            tmpbyte = dstValue;
            for (i = 0; i < 10; i++)
            {
                for (int j = 0; j < 102; j++)
                {
                    if (data_sp[i * 102 + j + 1] != tmpbyte)
                    {
                        ret = -1;
                        break;
                    }
                }

                tmpbyte += 1;
                if ((tmpbyte - 65) > 9)
                {
                    tmpbyte = 65;
                }

                if (ret == -1)
                {
                    break;
                }
            }

            return ret;
        }


        /// <summary>
        /// 创建要发送的测试帧
        /// </summary>
        /// <param name="frameno">这一帧的帧号</param>
        /// 帧的第一个字节为帧号：帧号从0开始到9
        /// 帧全长为1021个字节(第一个为帧号)从大写字母A一直循环到J
        /// 每个字母填充102个字节到帧中去，从那个字母开始根据帧号
        /// 决定。
        /// <returns></returns>
        public byte[] fun_CreateFrame(byte frameno)
        {
            byte[] send_buf = new byte[1021];

            int i;
            int j, k;

            j = frameno;
            k = 1;
            for (i = 0; i < 10; i++)
            {
                for (int z = 0; z < 102; z++)
                {
                    int h;

                    h = j + 'A';
                    send_buf[k] = (byte)h;
                    k += 1;
                }
                j += 1;
                if (j > 9)
                {
                    j = 0;
                }
            }

            send_buf[0] = frameno;
            return send_buf;
        }


        /// <summary>
        /// 获取目标机的信息
        /// </summary>
        /// <returns>返回-1表示处理失败了</returns>
        /// 作者:xhd
        /// 建立日期:09.10.29
        private int fun_SendGetDestInfoCmd()
        {
            int ret;

            ret = 0;
            
            byte[] xsendbuf;

            xsendbuf = new byte[] { 99, 111, 109, 109, 97, 110, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
            _SendClient.Send(xsendbuf, xsendbuf.Length, _DestCmdIp);

            _state = ThreadState.getdstinfo;

            return ret;
        }


        /// <summary>
        /// 从指令端口获取目标机器的信息
        /// </summary>
        /// <returns>返回-1表示处理失败了</returns>
        /// 作者:xhd
        /// 建立日期:09.10.20
        public int fun_GetDestInfo(byte [] xrecbuf)
        {
             
            uint tmp1;

            tmp1 = xrecbuf[0];
            tmp1 = (tmp1 << 8) | xrecbuf[1];
            tmp1 = (tmp1 << 8) | xrecbuf[2];
            tmp1 = (tmp1 << 8) | xrecbuf[3];

            _dstSystemSendCount = tmp1;

            tmp1 = xrecbuf[4];
            tmp1 = (tmp1 << 8) | xrecbuf[5];
            tmp1 = (tmp1 << 8) | xrecbuf[6];
            tmp1 = (tmp1 << 8) | xrecbuf[7];

            _dstSystemRecCount = tmp1;

            //越过错的数据

            tmp1 = xrecbuf[12];
            tmp1 = (tmp1 << 8) | xrecbuf[13];
            tmp1 = (tmp1 << 8) | xrecbuf[14];
            tmp1 = (tmp1 << 8) | xrecbuf[15];

            _dstRecCount = tmp1;

            tmp1 = xrecbuf[16];
            tmp1 = (tmp1 << 8) | xrecbuf[17];
            tmp1 = (tmp1 << 8) | xrecbuf[18];
            tmp1 = (tmp1 << 8) | xrecbuf[19];

            _dstSendCount = tmp1;

            return 1;
            
        }


        /// <summary>
        /// 取得目标机的信息线程
        /// </summary>
        /// <param name="param"></param>
        private void sub_ClsGetDstInfoThread(object param)
        {
            int retrycount = 0;
            int ret;
            string xmlstr = "";

            _lockthread.WaitOne();  //锁住信号没有释放
            
            fun_SendGetDestInfoCmd();


            runTimeOverTimer.Interval = 3 * 1000; //3秒
            runTimeOverTimer.Enabled = true;

            _RecClient = new UdpClient(_LocalRecPort + 1);
            IPEndPoint sendAddress = new IPEndPoint(IPAddress.Any, 0);
            byte[] buf;
            while (retrycount < 3)
            {
                try
                {
                    buf = _RecClient.Receive(ref sendAddress);
                }
                catch (Exception e)
                {
                    buf = null;
                }
                if (buf == null)
                {
                    if (_state == ThreadState.getdstinfoovertime)
                    {
                        //得到信息超时
                        retrycount += 1;
                        fun_SendGetDestInfoCmd();   //函数内部已经把_state状态改了
                        runTimeOverTimer.Interval = 3 * 1000; //3秒
                        runTimeOverTimer.Enabled = true;
                    }
                }
                else
                {
                    ret = fun_GetDestInfo(buf);
                    xmlstr = "driver_rec:" + _dstRecCount.ToString() + "-" + "driver_send:" + _dstSendCount.ToString() + "-";
                    xmlstr += "system_rec:" + _dstSystemRecCount.ToString() + "-" + "system_send:" + _dstSystemSendCount.ToString();
                    xmlstr += "-" + "local_rec:" + _recPackets.ToString() + "-" + "local_send:" + _sendPackets.ToString();
                    retrycount = 0;
                    break;
                }
            }

            if (retrycount >= 3)
            {
                xmlstr = "local_rec:" + _recPackets.ToString() + "-" + "local_send:" + _sendPackets.ToString();
            }
            runTimeOverTimer.Enabled = false;

            MF.xulog(MainForm.LogMsgType.Warning, xmlstr + "\n");
            _XML_cls.fun_WirteXML(MainForm.xmlevnet.testdata, System.DateTime.Now.ToString(), xmlstr);
            _state = ThreadState.testing;
            runTimeOverTimer.Interval = 60 * 1000;
            runTimeOverTimer.Enabled = true;

            _lockthread.Release();
 
        }

 
         /*public void Dispose()
         {
             _lockthread.WaitOne();  //锁住信号没有释放

             if (_state == ThreadState.testing)
             {
                 _XML_cls.fun_WirteXML(MainForm.xmlevnet.end, System.DateTime.Now.ToString(), null);
             }

             if (testRecThread.IsAlive)
             {
                 try
                 {
                     _SendClient.Close();
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine(e.ToString());
                 }
                 try
                 {
                     testRecThread.Suspend();
                     testRecThread.Abort();
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine(e.ToString());
                 }
                 //testRecThread.clos
             }
             if (testSendThread.IsAlive)
             {
                 _SendClient.Close();
                 try
                 {
                     testSendThread.Suspend();
                     testSendThread.Abort();
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine(e.ToString());
                 }
                 //testSendThread.Abort();
             }
             if (testGetDstInfoThread.IsAlive)
             {
                 _RecClient.Close();
                 try
                 {
                     testGetDstInfoThread.Suspend();
                     testGetDstInfoThread.Abort();
                 }
                 catch (Exception e)
                 {
                     Console.WriteLine(e.ToString());
                 }
             }
             _lockthread.Release();
         }*/

    }
}
